package gridmath;

import java.util.Vector; 

import preprocessing.WindowingSystem;


public abstract class AbstractCaseMatrix {
	
	protected WindowingSystem windowMaker;
	protected int noOfWindows;
	protected int maxDimension;
	
	protected double[] matrix1D;
	protected double[][] matrix2D;
	protected double[][][] matrix3D;
	protected double[][][][] matrix4D;
	 
	protected int i,j,k,m; //indices to matrix coordinates.
	protected int currentDimension;

	public AbstractCaseMatrix (WindowingSystem windowmaker, int maxD) {
		windowMaker = windowmaker;
		noOfWindows = windowMaker.getNoOfWindows();	
		maxDimension = maxD;
	}
	 
	/* 
	 * Sub-method called by calculate* method default implementations.
	 */
	public double doOperation(double operand, MatrixOperations operation) {
		System.err.println("Cannot perform operation on this object");
		return operand;
	}
	
	
	public double[] getMatrix1D() {
		return matrix1D;
	}

	/*
	 * Default implementation looks only for doOperation sub-method overload
	 * If you require a more involved implementation, overload this entire method.
	 */
	public void calculateMatrix1D (double[] operand1D, MatrixOperations operationType) {
		currentDimension = 1;
		for(i=0; i<noOfWindows; i++) {
			if(operand1D == null)
				matrix1D[i] = doOperation (0, operationType);
			else
				matrix1D[i] = doOperation(operand1D[i], operationType);
		}
	};

	public double[][] getMatrix2D() {
		return matrix2D;
	}

	/*
	 * Default implementation looks only for doOperation sub-method overload
	 * If you require a more involved implementation, overload this entire method.
	 */
	public void calculateMatrix2D(double[][] operand2D, MatrixOperations operationType) {
		currentDimension = 2;
		
		for(i=0; i<noOfWindows; i++) {
			for(j=i; j<noOfWindows; j++) {
				if(operand2D == null)
					matrix2D[i][j] = doOperation(0, operationType);
				else
					matrix2D[i][j] = doOperation(operand2D[i][j], operationType);
			}
		}
	};

	public double[][][] getMatrix3D() {
		return matrix3D;
	}

	/*
	 * Default implementation looks only for doOperation sub-method overload
	 * If you require a more involved implementation, overload this entire method.
	 */
	public void calculateMatrix3D(double[][][] operand3D, MatrixOperations operationType) {
		currentDimension = 3;
		
		for(i=0; i<noOfWindows; i++) {
			for(j=i; j<noOfWindows; j++) {
				for(k=j; k<noOfWindows; k++) {
					if(operand3D == null)
						matrix3D[i][j][k] = doOperation(0, operationType);
					else
						matrix3D[i][j][k] = doOperation(operand3D[i][j][k], operationType);
				}
			}
		}
	};

	public double[][][][] getMatrix4D() {
		return matrix4D;
	}

	/*
	 * Default implementation looks only for doOperation sub-method overload
	 * If you require a more involved implementation, overload this entire method.
	 */
	public void calculateMatrix4D (double[][][][] operand4D, MatrixOperations operationType) {
		currentDimension = 4;
		
		for(i=0; i<noOfWindows; i++) {
			for(j=i; j<noOfWindows; j++) {
				for(k=j; k<noOfWindows; k++) {
					for(m=k; m<noOfWindows; m++) {
						if(operand4D == null)
							matrix4D[i][j][k][m] = doOperation(0, operationType);
						else
							matrix4D[i][j][k][m] = doOperation(operand4D[i][j][k][m], operationType);
					}
				}
			}
		}
	};
 
	public int getWindows() {
		return noOfWindows;
	}
	
	//make return type a hashmap (key is coordinate int[], value is coordinate value)
	public Vector<int[]> getNonZeroCoordinates (int maxorder) {

		Vector<int[]> searchCoordinates = new Vector<int[]> ();
		
		for(int i=0; i<matrix1D.length; i++) {
			
			if(matrix1D[i] != 0)
				searchCoordinates.add ( new int[] {i} );
			if(maxorder<=1)
				continue;
			
			for(int j=i; j<matrix2D[i].length; j++){
			
				if(matrix2D[i][j] != 0)
					searchCoordinates.add ( new int[] {i,j} );
				if(maxorder<=2)
					continue;
				
				for(int k=j; k<matrix3D[i][j].length; k++) {
					
					if(matrix3D[i][j][k] != 0)
						searchCoordinates.add ( new int[] {i,j,k} );
					if(maxorder<=3)
						continue;
					
					for(int m=k; m<matrix4D[i][j][k].length; m++) {
						
						if(matrix4D[i][j][k][m] != 0)
							searchCoordinates.add ( new int[] {i,j,k,m} );
					
					}
				}
			}
		}
		
		return searchCoordinates;
	}

}
